#include "widget.h"
#include "ui_widget.h"

#include <QWidget>
#include <QMessageBox>
#include <QTcpSocket>
#include <QTcpServer> //将内核中已经建立好的链接获取到服务器

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //有链接，面向字节流，可靠
    //无连接，面向数据报，不可靠
    //listen: bind + listen，绑定端口号，并开始监听。
    //nextPendingConnection: accept，从内核中获取已经建立好的链接
    //newConnection: 信号，一定当有新客户端链接建立好后触发
    //QTcpSocket:
    //readAll：一次性读取接收缓冲区的所有数据
    //write(const QByteArray&)：把数据写入socket
    //udp操作的基本单位是QDatagram，tcp操作的基本单位是QByteArray
    //deletelater，把当前对象标记成无效，在下个循环中析构释放
    //readyRead，有数据到达并准备就绪的时候触发
    this->setWindowTitle("Tcp服务器");
    tcpserver = new QTcpServer(this); //创建tcp实例
    //一旦开始监听，客户端就可以进行链接了，要预先定义好怎样建立连接，怎样处理请求
    //绑定并监听是初始化的最后一步
    connect(tcpserver, &QTcpServer::newConnection, this, &Widget::processConnection);
    bool ret = tcpserver->listen(QHostAddress::Any, 8080);
    if(!ret)
    {
        QMessageBox::critical(this, "tcpserver fail to start", tcpserver->errorString());
        exit(1);
    }

 }

void Widget::processConnection()
{
    //1、通过tcpserver拿到一个socket对象，通过这个对象与客户端进行链接
    QTcpSocket* client_socket = tcpserver->nextPendingConnection();
    QString log = client_socket->peerAddress().toString() + " : " + QString::number(client_socket->peerPort()) + "] " + " 客户端上线";
    ui->listWidget->addItem(log);
    connect(client_socket, &QTcpSocket::readyRead, this, [=](){
        QString request = client_socket->readAll();
        QString response = processRequest(request);
        client_socket->write(response.toUtf8());
        QString log_info = "[ " + request.toUtf8() + "]: " + "客户端消息已到达";
        ui->listWidget->addItem(log_info);
    });
    connect(client_socket, &QTcpSocket::disconnected, this, [=](){
        QString log = client_socket->peerAddress().toString() + " : " + QString::number(client_socket->peerPort()) + "] " + " 客户端下线";
        client_socket->deleteLater(); //在下一轮事件循环中进行释放。
    });
}

QString& Widget::processRequest(QString& request)
{
    return request;
}

Widget::~Widget()
{
    delete ui;
}
